# coding: utf-8

import sqlite3
from itertools import chain

from ..log import Logger

log = Logger(__name__)


class SQLite:
    _instances = {}

    def __init__(self, path, defaulttable=None):
        self._uri = path + (('.' + defaulttable) if defaulttable else '')
        self._db = SQLite._instances.get(self._uri) or sqlite3.connect(path)
        SQLite._instances[self._uri] = self._db
        self._cur = self._db.cursor()
        self._defaulttable = defaulttable

    def close(self):
        self._cur.close()
        self._db.close()

    def getdefaulttable(self):
        if self._defaulttable is not None:
            return self._defaulttable
        else:
            return ValueError("you've not set a default table")

    def setdefaulttable(self, table):
        self._defaulttable = table

    def _exec(self, command, *args):
        log.d(command)
        return self._cur.execute(command, args)

    def _combine_conditions(self, conditions):
        if not conditions:
            return ''
        else:
            cond = (k + '=?' for k in conditions.keys())
            return ' WHERE ' + ' AND '.join(cond)

    def columns(self, table=None):
        table = table or self.getdefaulttable()
        self.select(table, id=0)
        return [row[0] for row in self._cur.description]

    def select(self, table=None, **conditions):
        table = table or self.getdefaulttable()
        cond = self._combine_conditions(conditions)
        self._exec('SELECT * FROM %s%s;' % (table, cond), *conditions.values())
        return self._cur.fetchall()

    def fetchdict(self, table=None, **conditions):
        cols = self.columns(table)
        for row in self.select(table, **conditions):
            yield dict(zip(cols, row))

    def insert(self, table=None, *args):
        """To use the default table and autoincrement primary key, do
            >>> db.insert(None, None, *remained_args)
        """
        table = table or self.getdefaulttable()
        self._exec('INSERT INTO %s VALUES(%s)'
                   % (table, ','.join('?' * len(args))),
                   *args)
        self._db.commit()

    def update(self, table=None, conditions={}, operations={}):
        """As example below, pass two dictionaies in, do
            >>> db.update(None, dict(id=1), dict(name='wick'))
        """
        table = table or self.getdefaulttable()
        changes = ','.join(k + '=?' for k in operations.keys())
        cond = self._combine_conditions(conditions)
        self._exec('UPDATE %s SET %s%s;' % (table, changes, cond),
                   *chain(operations.values(), conditions.values()))
        self._db.commit()

    def delete(self, table=None, **conditions):
        table = table or self.getdefaulttable()
        cond = self._combine_conditions(conditions)
        self._exec('DELETE FROM %s%s;' % (table, cond), *conditions.values())
        self._db.commit()
